package com.auto.survey.util

import android.app.Activity
import android.app.ActivityManager
import android.content.Context
import android.os.Build
import android.view.View
import com.auto.survey.activity.monitoring.entity.MonitoringPoint
import com.auto.survey.activity.monitoring.entity.Point
import com.auto.survey.activity.monitoring.modle.DoCollectedViewModle.Companion.KEY_MAP_MIRROR_TYPE
import com.auto.survey.activity.monitoring.modle.DoCollectedViewModle.Companion.KEY_MAP_POINT_HIGHT
import com.auto.survey.activity.monitoring.modle.DoCollectedViewModle.Companion.KEY_MAP_POINT_HZ
import com.auto.survey.activity.monitoring.modle.DoCollectedViewModle.Companion.KEY_MAP_POINT_SD
import com.auto.survey.activity.monitoring.modle.DoCollectedViewModle.Companion.KEY_MAP_POINT_VA
import com.auto.survey.activity.monitoring.modle.DoCollectedViewModle.Companion.KEY_MAP_POINT_X
import com.auto.survey.activity.monitoring.modle.DoCollectedViewModle.Companion.KEY_MAP_POINT_Y
import com.auto.survey.activity.monitoring.modle.DoCollectedViewModle.Companion.KEY_MAP_POINT_Z
import org.json.JSONArray
import org.json.JSONObject
import java.text.DecimalFormat
import java.text.SimpleDateFormat
import java.time.Instant
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.util.Date
import java.util.Locale
import kotlin.math.cos
import kotlin.math.sin

object Helper {

    /**
     * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
     *
     * @param context 上下文
     * @param dpValue dp值
     */
    fun dip2px(context: Context, dpValue: Float): Int {
        val scale = context.resources.displayMetrics.density
        return (dpValue * scale + 0.5f).toInt()
    }

    /**
     * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
     *
     * @param context 上下文
     * @param pxValue px值
     */
    fun px2dip(context: Context, pxValue: Float): Int {
        val scale = context.resources.displayMetrics.density
        return (pxValue / scale + 0.5f).toInt()
    }

    /**
     * px转sp
     *
     * @param context 上下文
     * @param pxValue px值
     * @return
     */
    fun px2sp(context: Context, pxValue: Float): Int {
        val fontScale = context.resources.displayMetrics.scaledDensity
        return (pxValue / fontScale + 0.5f).toInt()
    }

    /**
     * sp转px
     *
     * @param context 上下文
     * @param spValue sp值
     * @return
     */
    fun sp2px(context: Context, spValue: Float): Int {
        val fontScale = context.resources.displayMetrics.scaledDensity
        return (spValue * fontScale + 0.5f).toInt()
    }

    // 防抖动高阶函数
    fun debounce(waitMs: Long = 1000L,action: (View) -> Unit): (View) -> Unit {
        var lastClickTime: Long? = null // 使用可空类型，延迟初始化
        return { view ->
            val currentTime = System.currentTimeMillis()
            if (lastClickTime == null || currentTime - lastClickTime!! >= waitMs) {
                lastClickTime = currentTime
                action(view)
            }
        }
    }

    /**
     * 判断当前activity是否在运行
     *
     * @param mContext
     * @param activityClassName
     * @return
     */
    fun isActivityRunning(mContext: Activity, activityClassName: String): Boolean {
        val activityManager = mContext.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
        val info = activityManager.getRunningTasks(1)
        if (info != null && info.size > 0) {
            val component = info[0].topActivity
            val classname = component!!.className
            return classname == activityClassName
        } else {
            return false
        }
    }

    /**
     * 将时间戳转换为指定格式的字符串
     * @param timestamp 时间戳（毫秒）
     * @param pattern 日期格式，默认 "yyyy-MM-dd"
     * @return 格式化的日期字符串
     */
    @JvmOverloads
    fun formatTimestamp(timestamp: Long, pattern: String = "yyyy-MM-dd"): String {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // API 26+ 使用 java.time 包
            val zonedDateTime = Instant.ofEpochMilli(timestamp)
                .atZone(ZoneId.systemDefault())
            val formatter = DateTimeFormatter.ofPattern(pattern)
            zonedDateTime.format(formatter)
        } else {
            // API 26- 使用 SimpleDateFormat
            val sdf = SimpleDateFormat(pattern, Locale.getDefault())
            sdf.format(Date(timestamp))
        }
    }

    /**
     * 字节数组转换为十六进制字符串
     *
     * @param b
     * byte[] 需要转换的字节数组
     * @return String 十六进制字符串
     */
    fun byte2hex(b: ByteArray): String {
        requireNotNull(b) { "Argument b ( byte array ) is null! " }

        var hs = ""

        var stmp = ""

        for (n in b.indices) {
            stmp = Integer.toHexString(b[n].toInt() and 0xff)

            hs = if (stmp.length == 1) {
                hs + "0" + stmp
            } else {
                hs + stmp
            }
        }

        return hs.uppercase(Locale.getDefault())
    }


    fun formateDecimal(number: Double?, format: String = "#.####"):Double {
        val df = DecimalFormat(format)
        return df.format(number).toDouble()
    }

    fun parseJson(json:String?):List<String> {
        val list = mutableListOf<String>()
        try {
            val jsonArray = JSONArray(json)
            for (i in 0..<jsonArray.length()) {
                val value = jsonArray.opt(i)
                list.add(value.toString())
            }
        } catch (e:Exception) {
            e.printStackTrace()
        }

        return list
    }

    /**
     * 将弧度转换为度分秒格式
     * @param radians 弧度值
     * @return 包含度、分、秒的 Triple
     */
    fun radiansToDMS(radians: Double): Triple<Int, Int, Double> {
        // 先将弧度转换为角度
        val degrees = Math.toDegrees(radians)

        // 提取度
        val wholeDegrees = degrees.toInt()

        // 提取分
        val minutesTemp = (degrees - wholeDegrees) * 60
        val wholeMinutes = minutesTemp.toInt()

        // 提取秒
        val seconds = (minutesTemp - wholeMinutes) * 60

        return Triple(wholeDegrees, wholeMinutes, seconds)
    }

    /**
     * 将弧度转换为度分秒格式的字符串表示
     * @param radians 弧度值
     * @param showSymbol 是否显示度分秒符号
     * @return 度分秒格式的字符串
     */
    fun radiansToDMSString(radians: Double, showSymbol: Boolean = true): String {
        val (degrees, minutes, seconds) = radiansToDMS(radians)

        return if (showSymbol) {
            "${degrees}° ${minutes}′ ${formateDecimal(seconds, "##.#")}″"
        } else {
            "$degrees $minutes $seconds"
        }
    }

    /**
     * 度转成秒
     */
    fun radiansToSecond(radians: Double):Double {
        val (degrees, minutes, seconds) = radiansToDMS(radians)
        return formateDecimal((degrees * 60 * 60 + minutes*60 + seconds), "##")
    }

    fun jsonToPoint(json:String, point: Point, objId:Int, stationId:Int, maxcount: Int):MonitoringPoint {
        //{"KEY_MAP_POINT_SD":2.9816,"KEY_MAP_POINT_Y":860.7849,"KEY_MAP_POINT_X":1393.0453,"KEY_MAP_POINT_HZ":0.621620494047055,"KEY_MAP_POINT_HIGHT":0.0,"KEY_MAP_POINT_VA":1.620390744175635,"KEY_MAP_POINT_Z":12.8902}
        val jsonObject = JSONObject(json)
        val hz = jsonObject.optDouble(KEY_MAP_POINT_HZ)
        val va = jsonObject.optDouble(KEY_MAP_POINT_VA)
        val sd = jsonObject.optDouble(KEY_MAP_POINT_SD)
        val hight = jsonObject.optDouble(KEY_MAP_POINT_HIGHT)
        val mirrorType = jsonObject.optDouble(KEY_MAP_MIRROR_TYPE)
        val x = jsonObject.optDouble(KEY_MAP_POINT_X)
        val y = jsonObject.optDouble(KEY_MAP_POINT_Y)
        val z = jsonObject.optDouble(KEY_MAP_POINT_Z)

        val mointoringPoint = MonitoringPoint(monitoringObjectId= objId, stationId = stationId,
            pointName = point.pointName, pointCode = "", pointX = x, pointY = y, pointZ = z,
            collected = true, pointHz = hz, pointV = va, pointSD = sd, mirrorHeight = hight,
            pointType = point.pointType, isWarning=false,mirrorType = mirrorType.toInt(),
            createTime= formatTimestamp(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss"),
            updateTime="",measurementOrder=maxcount+1)


        return mointoringPoint
    }

    fun degrees(radians: Double): String {
        val deg = Math.toDegrees(radians)
        val d = deg.toInt()
        val m = ((deg - d) * 60).toInt()
        val s = ((deg - d - m / 60.0) * 3600)
        return "${d}°${m}'${s.toString().substring(0, minOf(5, s.toString().length - 1))}\""
    }


    /**
     * 计算2C值（视准轴误差的两倍）
     * @param horizontalAngleL 盘左水平角（弧度）
     * @param horizontalAngleR 盘右水平角（弧度）
     * @return 2C值（弧度）
     */
    fun calculateC2Value(horizontalAngleL: Double, horizontalAngleR: Double): Double {
        return horizontalAngleL - (horizontalAngleR - Math.PI)
    }

    /**
     * 计算指标差（垂直角观测误差）
     * @param verticalAngleL 盘左垂直角（弧度）
     * @param verticalAngleR 盘右垂直角（弧度）
     * @return 指标差（弧度）
     */
    fun calculateIndexError(verticalAngleL: Double, verticalAngleR: Double): Double {
        return (verticalAngleL + verticalAngleR - Math.PI) / 2
    }

    /**
     * 计算平距（水平距离）
     * @param slopeDistance 斜距（米）
     * @param verticalAngle 垂直角（弧度）
     * @return 平距（米）
     */
    fun calculateHorizontalDistance(slopeDistance: Double, verticalAngle: Double): Double {
        return slopeDistance * cos(verticalAngle)
    }

    /**
     * 计算高差
     * @param slopeDistance 斜距（米）
     * @param verticalAngle 垂直角（弧度）
     * @param instrumentHeight 仪器高（米）
     * @param prismHeight 棱镜高（米）
     * @return 高差（米）
     */
    fun calculateHeightDifference(
        slopeDistance: Double,
        verticalAngle: Double,
        instrumentHeight: Double,
        prismHeight: Double
    ): Double {
        return slopeDistance * sin(verticalAngle) + instrumentHeight - prismHeight
    }

    /**
     * 计算多边形角度闭合差
     * @param observedAngles 观测角度列表（弧度）
     * @param theoreticalSum 理论角度和（弧度）
     * @return 角度闭合差（弧度）
     */
    fun calculateAngleClosure(observedAngles: List<Double>, theoreticalSum: Double): Double {
        return observedAngles.sum() - theoreticalSum
    }

    /**
     * 计算理论多边形内角和
     * @param n 边数
     * @return 理论内角和（弧度）
     */
    fun calculateTheoreticalPolygonSum(n: Int): Double {
        return (n - 2) * Math.PI
    }
}